import {HttpClient} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {FormControl} from '@angular/forms';
import {Observable} from 'rxjs/Observable';

import 'rxjs/add/observable/timer';
import 'rxjs/add/operator/switchMap';

export const VAILDATOR_COMMON = {
  USER_CODE_LEG: {
    MAX: 50
  },
  // 编辑器
  EDIT_MAX_LEG_TIP: '最大输入10000字符',
  // 邮箱
  EMAIL_TIP: '格式不正确',
  // 邮编
  ZIPCODE_TIP: /^[0-9]{6}$/,
  ZIPCODE_TIP_MESS: '请输入6位数字',
  EMAIL_TIPS: '最大输入90字符',
  EMAIL_REGEXP: /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i,
  EMAI_LEG: {
    MAX: 90
  },
  // 固定电话号码
  TEL_NOEXIT_TIP: '您输入的手机号不存在，请核对后重新输入',
  TEL_TIP: '格式不正确（区号-电话号码）',
  TEL_REGEXP: /(^0(\d{2})[2-9](\d{7})$)|(^0(\d{3})[2-9](\d{6})$)/,
  TEL_LANDLINE: /0\d{2,3}-\d{7,8}$/,
  // 手机号
  PHONE_TIP: '请输入正确的手机号格式',
  PHONE_REGEXP: /^((1[3,5,8][0-9])|(14[5,7])|(17[0,3,6,7,8])|(19[7,8,9])|(16[6]))\d{8}$/,
  // 手机验证码:4位数字
  CODE_TIP: '请输入4位数字',
  CODE_REGEXP: /^\d{4}$/,
  // 用户账号：2至12位大小写字母和数字
  ACCOUNT_TIP: '请输入2至12位汉字、大小写字母或数字',
  ACCOUNT_REGEXP: /^[\u4e00-\u9fa5a-zA-Z0-9]{2,12}$/,
  ACCOUNT_LEG: {
    MIN: 2,
    MAX: 12
  },
  // 用户密码：6至20位大小写字母和数字
  PSW_TIP: '字母或数字',
  PSW_REGEXP: /^[a-zA-Z0-9]{6,20}$/,
  PSW_LEG: {
    MIN: 6,
    MAX: 20
  },
  // Code代码
  DIC_CODE_DiGIT_TIP: '只允许1位数字', // author：P.J，remark：一位数字
  DIC_CODE_DiGIT: /^\d{1}$/, // author：P.J，remark：一位数字
  BANK_CODETIP: '只允许2位数字', // author：P.J，remark：2位数字
  BANK_CODE_REGEXP: /^(\d{2})$/, // author：P.J，remark：2位数字
  // 2至6位纯数字
  BANK_CODE_TIP: '只允许2至6位数字', // author：P.J，remark：2到6位数字
  BANK_CODENUM_REGEXP: /^(\d{2,6})$/, // author：P.J，remark：2到6位数字
  // 2至3位纯数字
  BANK_CODE_MSG: '只允许2至3位数字', // author：P.J，remark：2到3位数字
  BANK_CODE_TWO_THREE: /^(\d{2,3})$/, // author：P.J，remark：2到3位数字
  DIC_CODE_TIP: '只允许字母、数字或短横线（-）',
  DIC_CODE_REGEXP: /^[a-zA-Z\d-]+$/,
  CODEMAX_TIP: '最大输入12个字符',
  DIC_CODE_LEG: {
    MIN: 1,
    MAX: 12
  },
  // 报账编号
  RMB_CODE_REGEXP: /^[a-zA-Z\d-]{6,20}$/,
  RMB_CODE_TIP: '请输入6至20位字母、数字或短横线（-）',
  RMB_CODE_LEG: {
    MIN: 6,
    MAX: 20
  },
  // 真实姓名:2至16位汉字
  REALNAME_TIP: '请输入2至16位汉字',
  REALNAME_REGEXP: /^([\u4e00-\u9fa5]){2,16}$/,
  // 身份证号
  ID_CARD_TIP: '格式不正确',
  ID_CARD_REGEXP: /^[1-9][0-9]{5}(19|20)[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|30|31)|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}([0-9]|x|X)$/,
  // ID_CARD_REGEXP: /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
  // 单位名称：1至50位汉字、大小写字母和数字
  COM_NAME_TIP: '请输入1至50位汉字、大小写字母或数字',
  COM_NAME_REGEXP: /^[\u4e00-\u9fa5A-Za-z0-9]{1,50}$/,
  COM_NAME_LEG: {
    MAX: 50
  },
  // 单位营业执照号
  COM_LIC_TIP: '请输入15至18位数字或大写字母',
  COM_LIC_REGEXP: /^(?:(?![IOZSV])[\dA-Z]){2}\d{6}(?:(?![IOZSV])[\dA-Z]){7,10}$/,
  // 银行账户：6至22位纯数字
  BANK_NUM_TIP: '请输入6至22位数字',
  BANK_NUM_REGEXP: /^(\d{6,22})$/,
  // 地址：1至100位字符
  ADDRESS_TIP: '最大可输入100个字符',
  ADDRESS_REGEXP: /^[\s\S]{1,100}$/,
  ADDRESS_LEG: {
    MAX: 100
  },
  // 标题：1至50位汉字、大小写字母和数字
  TITLE_TIPS: '最大可输入50个字符',
  TITLE_TIP: '请输入汉字、大小写字母或数字',
  TITLE_REGEXP: /^[\u4e00-\u9fa5A-Za-z0-9]{1,50}$/,
  TITLE_LEG: {
    MAX: 50
  },
  MORE_PERSON_TIP: '请输入2至50位汉字（顿号隔开）',
  MORE_PERSON_REGEXP: /^[\u4e00-\u9fa5、]{2,50}$/,
  CON_NAME_REGEXP: /^[\u4e00-\u9fa5A-Za-z0-9]{1,36}$/,
  CON_NAME_LEG: {
    MAX: 36
  },
  // textarea文本框：1至5000位字符
  TEXTAREA_TIP: '最大可输入5000个字符',
  TEXTAREA_TEXTAREAREQ: '必填项',
  TEXTAREA_REGEXP: /^[\s\S]{1,5000}$/,
  TEXTAREA_LEG: {
    MAX: 5000
  },
  SUGGESTION_TIP: '最大可输入90个字符',
  SUGGESTION_REAREQ: '必填项',
  SUGGESTION_REGEXP: /^[\s\S]{1,90}$/,
  SUGGESTION_LEG: {
    MAX: 90
  },
  // 技术参数
  SPEC_TIP: '最大可输入10000个字符',
  SPEC_REGEXP: /^[\s\S]{1,10000}$/,
  SPEC_LEG: {
    MAX: 10000
  },
  // 校验存在
  EXIT_TIP: '已经存在，请重新输入',
  // 校验存在
  EXIT_TIP_SELECT: '已经存在，请重新选择',
  // 无效字符
  NOVOLID: '请输入汉字、符号、大小写字母或数字',
  // 日期不能为空
  DATEREQUIRE: '日期不能为空',
  // 时间不能为空
  TIMEREQUIRE: '时间不能为空',
  // 验证中...
  VALIDATE_TIP: '校验中...',
  // 服务器异常
  SERVER_TIP: '服务器校验异常',
  // input 为必填项
  INPUT_REQUIRE: '必填项',
  // select 为必填项
  SELECT_REQUIRE: '必选项',
  // 数字: 正整数
  NUMBER_REGEXP: /^([0-9]*[1-9][0-9]*)$/,
  // 数字
  NUMBER_ALL_REGEXP: /^[0-9]+.?[0-9]*$/,
  // 数字: 正数，小数点不超过两位
  PRICE_REGEXP: /^((([1-9][0-9]*)|(([0]\.\d{1,2}|[1-9][0-9]*\.\d{1,2}))))$/,
  // 单位注册资金（万）：1至8位正整数（首数字不能为0）
  COM_CAPITAL_TIP: '请输入1至8位数字（首数字不能为0）',
  COM_CAPITAL_REGEXP: /^([1-9](\d{0,7}))$/,
  // 超短名称：1至10位字符
  Small_NAME_REGEXP: /^([\s\S]){1,10}$/,
  Small_NAME_LEG: {
    MIN: 1,
    MAX: 10
  },
  // 短名称：2至12位字符
  SHORT_NAME_REGEXP: /^([\s\S]){2,12}$/,
  SHORT_NAME_LEG: {
    MIN: 2,
    MAX: 12
  },
  // 链接校验正则
  COMMON_LINK_REGEXP: /^((ht|f)tps?):\/\/[-A-Za-z0-9+&amp;@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&amp;@#\/%=~_|]$/,
  COMMON_LINK_LEG: {
    MIN: 2,
    MAX: 200
  },
  LINK_TIP: '链接格式不正确',
  // 一般中长度名称：2至30位字符
  COMMON_NAME_REGEXP: /^([\s\S]){2,30}$/,
  COMMON_NAME_LEG: {
    MIN: 2,
    MAX: 30
  },
  // 长名称：2至50位
  LONG_NAME_REGEXP: /^([\s\S]){2,50}$/,
  LONG_NAME_LEG: {
    MIN: 2,
    MAX: 50
  },
  // 附加条款名称：2至40位
  CONADD_NAME_REGEXP: /^([\s\S]){2,40}$/,
  CONADD_NAME_LEG: {
    MIN: 2,
    MAX: 40
  },
  // 只能輸入數字
  CONAMOUNT_TIP: '只能输入数字',
  CONAMOUNT: /^[0-9]+([.]{1}[0-9]+)?$/,
  // 支付比例 1到100
  PAY_PERCENT_TIP: '请输入1到100之间的或数字',
  // PAY_PERCENT: /^(([1-9]\d?)|100)$/,
  // 项目名称
  PRO_NUM_TIP: '请输入字母或数字',
  PRO_NUM_REGEXP: /^[a-zA-Z0-9]*$/,
  PRO_NUM_LEG: {
    MIN: 0,
    MAX: 20
  },
};
// 返回一个null的Observable对象
export const dealWithNoRequired = (control: FormControl, callback) => {
  if ((control && control.value === '') || (control && control.value === null)) {
    return Observable.create((observer) => {
      observer.next(null);
      observer.complete();
    });
  } else {
    return callback;
  }
};
export const VALID = {
  VALID_COMMON: (control, key) => {
    if (!control.value) {
      return {required: true};
    } else if (!VAILDATOR_COMMON[key].test(control.value)) {
      return {error: true, [key]: true};
    }
  },
  VALID_COMMON_NO_REQUIRED: (control, key) => {
    // if (control.value.length === 0) {
    if (!control.value) {
      return;
    } else if (!VAILDATOR_COMMON[key].test(control.value)) {
      return {error: true, [key]: true};
    }
  }
};
// 身份证严格验证
export const ID_CARD_VALID = {
  IdentityCodeValid: (code) => {
    const city = {
      11: '北京',
      12: '天津',
      13: '河北',
      14: '山西',
      15: '内蒙古',
      21: '辽宁',
      22: '吉林',
      23: '黑龙江 ',
      31: '上海',
      32: '江苏',
      33: '浙江',
      34: '安徽',
      35: '福建',
      36: '江西',
      37: '山东',
      41: '河南',
      42: '湖北 ',
      43: '湖南',
      44: '广东',
      45: '广西',
      46: '海南',
      50: '重庆',
      51: '四川',
      52: '贵州',
      53: '云南',
      54: '西藏 ',
      61: '陕西',
      62: '甘肃',
      63: '青海',
      64: '宁夏',
      65: '新疆',
      71: '台湾',
      81: '香港',
      82: '澳门',
      91: '国外'
    };
    const result = VALID.VALID_COMMON(code, 'ID_CARD_REGEXP');
    if (result) {
      return result;
    }
    code = code.value.toUpperCase();
    if (!city[code.substr(0, 2)]) {
      return {error: true, ID_CARD_REGEXP: true};
    } else {
      // 18位身份证需要验证最后一位校验位
      if (code.length === 18) {
        code = code.split('');
        // ∑(ai×Wi)(mod 11)
        // 加权因子
        const factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
        // 校验位
        const parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2];
        let sum = 0;
        let ai = 0;
        let wi = 0;
        for (let i = 0; i < 17; i++) {
          ai = code[i];
          wi = factor[i];
          sum += ai * wi;
        }
        const last = parity[sum % 11];
        if (last !== code[17]) {
          return {error: true, ID_CARD_REGEXP: true};
        }
      } else if (code.length === 15) {
        if (!/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/.test(code)) {
          return {error: true, ID_CARD_REGEXP: true};
        }
      } else {
        return {error: true, ID_CARD_REGEXP: true};
      }
    }
  }
};

@Injectable()
// 验证去重的http请求
export class AsyncValidator {

  constructor(private http: HttpClient) {
  }

  commonAsyncValidator = (url: string, data: object, successFun: Function, errorFun: Function): any => {
    return Observable.timer(800).switchMap(() =>
      Observable.create((observer) => {
        this.http.post(localStorage.getItem(`httpDomain`) + `${url}`, data)
          .subscribe(v => {
            successFun(observer, v);
          }, () => {
            errorFun(observer);
          });
      })
    );
  }
}
